﻿using CommonTools;
using LockheedMartin.Prepar3D.SimConnect;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;

namespace SimLib
{
    /// <summary>
    /// 使用simconnect 控件飞机相关
    /// </summary>
    public class SimControl
    {
        ~SimControl()
        {
            if (handleSource != null)
            {
                handleSource.RemoveHook(HandleSimConnectEvents);
            }
        }
        const int WN_USER_SIMCONNECT = 0x0402;
        HwndSource handleSource;
        System.Timers.Timer autoConectedSim;
        /// <summary>
        /// 窗口句柄，提供给Sim
        /// </summary>
        IntPtr handle;
        /// <summary>
        /// sim连接
        /// </summary>
        private static SimConnect simConnect = null;
        /// <summary>
        /// UDP地址
        /// </summary>
        private static UdpClient udpClient = null;
        #region 初始化
        private IPEndPoint remoteEP;
        /// <summary>
        /// 连接p3d
        /// </summary>
        private  void connectP3d()
        {
            try
            {
                simConnect = new SimConnect("controlSim", handle, WN_USER_SIMCONNECT, null, 1);
                InitSubscribeToSystemEvent();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private IntPtr HandleSimConnectEvents(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool isHandled)
        {
            isHandled = false;

            switch (message)
            {
                case WN_USER_SIMCONNECT:
                    {
                        if (simConnect != null)
                        {
                            simConnect.ReceiveMessage();
                            isHandled = true;
                        }
                    }
                    break;

                default:
                    break;
            }

            return IntPtr.Zero;
        }
        /// <summary>
        /// 打开SIM,打开 udp
        /// </summary>
        /// <param name="instructorIPEndPoint">接收数据地址</param>
        public void Start(IntPtr handle,string instructorIPEndPoint)
        {
            handleSource = HwndSource.FromHwnd(handle); // Get source of handle in order to add event handlers to it
            handleSource.AddHook(HandleSimConnectEvents);
            this.handle = handle;

            autoConectedSim = new System.Timers.Timer();
            autoConectedSim.Interval = 5000;
            autoConectedSim.Elapsed += AutoConectedSim_Elapsed;
            autoConectedSim.Start();

            remoteEP = CommonTool.CvStr2IPEndPoint(instructorIPEndPoint);
            try
            {
                if (udpClient != null)
                    return;
                IPEndPoint locatePoint = new IPEndPoint(IPAddress.Parse(CommonTool.GetIpAddress()), 9000);
                udpClient = new UdpClient(locatePoint);
                Thread udpReceive = new Thread(UDPRecvMessage);
                udpReceive.SetApartmentState(ApartmentState.STA);
                udpReceive.IsBackground = true;
                udpReceive.Start();
            }
            catch (Exception)
            {
            }
        }

        private void AutoConectedSim_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            connectP3d();
        }

        /// <summary>
        /// udp发送方法
        /// </summary>
        /// <param name="sendmessage"></param>
        /// <param name="ep"></param>
        public static void UDPSendMessage(string sendmessage, IPEndPoint ep)
        {
            try
            {
                byte[] sendmess = Encoding.UTF8.GetBytes(sendmessage);
                var ss = udpClient.Send(sendmess, sendmess.Length, ep);
            }
            catch (Exception e)
            {
                Console.WriteLine("发送失败！" + e.ToString());
            }
        }
        #region 系统事件
        /// <summary>
        /// 初始化订阅系统事件
        /// </summary>
        private void InitSubscribeToSystemEvent()
        {
            #region adjustGague 事例初始声明
            simConnect.MapClientEventToSimEvent(SystemEvent.SITUATION_RESET, "SITUATION_RESET");
            simConnect.AddClientEventToNotificationGroup(SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT, false);


            #endregion
            // listen to events
            simConnect.OnRecvEvent += new SimConnect.RecvEventEventHandler(simconnect_OnRecvEvent);
            simConnect.OnRecvEventText += new SimConnect.RecvEventTextEventHandler(simconnect_OnTextEvent);


            simConnect.OnRecvPlaybackStateChanged += Simconnect_OnRecvPlaybackStateChanged;
            simConnect.OnRecvRecorderStateChanged += Simconnect_OnRecvRecorderStateChanged;
            simConnect.SubscribeToSystemEvent(SystemEvent.RecorderStateChanged, "RecorderStateChanged");
            simConnect.SubscribeToSystemEvent(SystemEvent.PlaybackStateChanged, "PlaybackStateChanged");
            simConnect.SubscribeToSystemEvent(SystemEvent.SIMSTART, "SimStart");
            simConnect.SubscribeToSystemEvent(SystemEvent.SIMSTOP, "SimStop");
        }

        private void simconnect_OnTextEvent(SimConnect sender, SIMCONNECT_RECV_EVENT_TEXT data)
        {
        }

        private void simconnect_OnRecvEvent(SimConnect sender, SIMCONNECT_RECV_EVENT data)
        {
            SIMCONNECT_RECV_RECORDER_STATE_CHANGED da = (SIMCONNECT_RECV_RECORDER_STATE_CHANGED)data;
        }

        private void Simconnect_OnRecvRecorderStateChanged(SimConnect sender, SIMCONNECT_RECV_RECORDER_STATE_CHANGED data)
        {
            string retureData = "Recording" + ":" + data.hasRecordingStarted;
            UDPSendMessage(retureData, remoteEP);
        }
        private void Simconnect_OnRecvPlaybackStateChanged(SimConnect sender, SIMCONNECT_RECV_PLAYBACK_STATE_CHANGED data)
        {
            string retureData = "PlayBack" + ":" + data.hasPlaybackStarted;
            UDPSendMessage(retureData, remoteEP);
        }
        #endregion

        #endregion
        /// <summary>
        /// UPD接收数据处理方法
        /// </summary>
        private void UDPRecvMessage()
        {
            IPEndPoint temp = null;
            while (true)
            {
                try
                {
                    byte[] receiveBytes = udpClient.Receive(ref temp);
                    string receiveMessage = Encoding.UTF8.GetString(receiveBytes, 0, receiveBytes.Length);
                    string[] ss = receiveMessage.Split(new char[] { ':' });
                    switch (ss[0])
                    {
                        case "StartRecording":
                            {
                                simConnect.StartRecorder();
                            }
                            break;
                        case "StopRecording":
                            {
                                simConnect.StopRecorderAndSaveRecording(ss[1], ss[3], false);
                                string retureData = "SaveRecording" + ":" + ss[1]+":" + ss[2] + ":" + ss[3];
                                UDPSendMessage(retureData, remoteEP);
                            }
                            break;
                        case "PlayBack":
                            {
                                string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Prepar3D v4 Files\" + ss[1];
                                //检测文件是否存在,回放状态为0
                                if (File.Exists(path))
                                {
                                    simConnect.PlaybackRecording(path, 0, -1, false);
                                }
                            }
                            break;
                        case "Save":
                            {
                                simConnect.FlightSave(ss[1],ss[2], ss[3],0);
                                string retureData = "Save" + ":" + ss[1] + ":" + ss[2] + ":" + ss[3];
                                UDPSendMessage(retureData, remoteEP);
                            }
                            break;
                        case "FiveSideSave":
                            {
                                simConnect.FlightSave(ss[1], ss[1], ss[1], 0);
                                string retureData = "FiveSideSave" + ":" + ss[1];
                                UDPSendMessage(retureData, remoteEP);
                            }
                            break;
                        case "Reset":
                            {
                                simConnect.TransmitClientEvent64(SimConnect.SIMCONNECT_OBJECT_ID_USER, SystemEvent.SITUATION_RESET, 0, SIMCONNECT_DATA_SET_FLAG.DEFAULT, SIMCONNECT_EVENT_FLAG.DEFAULT);
                            }
                            break;
                        case "FlightLoad":
                            {
                                simConnect.FlightLoad(ss[1]);
                            }
                            break;
                        default:
                            {
                                Console.WriteLine("Commend can't identify!");
                                break;
                            }
                    }
                }
                catch
                {
                }
            }
        }
    }
}
